<?php
/*
 * Copyright (c) 2023. ogg. Inc. All Rights Reserved.
 * ogg sit down and start building bugs in sunny weather.
 * Author: Tc <1224663799@qq.com>.
 * LastChangeTime: 2023-01-16 06:18:52
 * ChangeTime: 2023-04-26 10:21:30
 */

declare(strict_types=1);

namespace Hesb\LaravelPlus\Helpers;

use Hesb\LaravelPlus\Annotation\AnnotationInterface;
use Hesb\LaravelPlus\AnnotationReader;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\ParserFactory;
use PhpParser\PhpVersion;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;
use ReflectionClass;

class CollectHelper
{
    protected AnnotationReader $reader;

    public function __construct(){
        $this->reader = make(AnnotationReader::class);
    }


    public function scan(){
        $appDir = app()->path();
        $files = $this->scanForFiles($appDir);
        foreach ($files as $file) {
             $this->collect($file);
        }
    }

    private function getFiles($dir) {
        $files = [];
        $handle = opendir($dir);

        while (false !== ($file = readdir($handle))) {
            if ($file != "." && $file != "..") {
                $path = $dir.'/'.$file;

                if (is_dir($path)) {
                    $files = array_merge($files, self::getFiles($path));
                } else {
                    $files[] = $path;
                }
            }
        }
        closedir($handle);
        return $files;
    }


    //扫描文件
    public function scanForFiles(string $basePath): array
    {
//        $directoryIterator = new RecursiveDirectoryIterator($basePath);
//        $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);
//
//        $files = [];
//        foreach ($recursiveIterator as $file) {
//            /** @var SplFileInfo $file */
//            if ($file->isDir()) {
//                continue;
//            }
//            $files[] = $file->getPathname();
//        }

        return $this->getFiles($basePath);
    }

    //扫描文件Controller
    public function scanForController(string $basePath): array
    {
//        $directoryIterator = new RecursiveDirectoryIterator($basePath);
//        $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);
//
//        $files = [];
//        foreach ($recursiveIterator as $file) {
//            /** @var SplFileInfo $file */
//            if ($file->isDir()) {
//                continue;
//            }
//            $files[] = $file->getPathname();
//        }

        $files =  $this->getFiles($basePath);
        $controllerFiles = [];
        foreach($files as $file){
            if (str_contains($file, 'Controller.php')) {
                $controllerFiles[] = $file;
            }
        }
        return $controllerFiles;
    }

    //收集注解
    public function collect($file){
        //$className = $this->getPhpNamespace($file);
        $className = NamespaceHelper::path2namespace($file);
        if(empty($className)) return;
        $reflection = new ReflectionClass($className);
        // Parse class annotations
        $classAnnotations = $this->reader->getClassAnnotations($reflection);
        if (! empty($classAnnotations)) {
            make($className);
            foreach ($classAnnotations as $classAnnotation) {
                if($classAnnotation instanceof AnnotationInterface){
                    $classAnnotation->collectClass($className);
                }
            }
        }
        // Parse properties annotations
        $properties = $reflection->getProperties();
        foreach ($properties as $property) {
            $propertyAnnotations = $this->reader->getPropertyAnnotations($property);
            if (! empty($propertyAnnotations)) {
                foreach ($propertyAnnotations as $propertyAnnotation) {
                    if ($propertyAnnotation instanceof AnnotationInterface) {
                        $propertyAnnotation->collectProperty($className, $property->getName());
                    }
                }
            }
        }
        // Parse methods annotations
        $methods = $reflection->getMethods();
        foreach ($methods as $method) {
            $methodAnnotations = $this->reader->getMethodAnnotations($method);
            if (! empty($methodAnnotations)) {
                foreach ($methodAnnotations as $methodAnnotation) {
                    if ($methodAnnotation instanceof AnnotationInterface) {
                        $methodAnnotation->collectMethod($className, $method->getName());
                    }
                }
            }
        }
    }

    private function getPhpNamespace($filepath) {
        $parserFactory = new ParserFactory();
        $astParser = $parserFactory->createForVersion(PhpVersion::getHostVersion());
        $stmts = $astParser->parse(file_get_contents($filepath));
        return $this->parseClassByStmts($stmts);
    }

    private function parseClassByStmts(array $stmts): string
    {
        $namespace = $className = '';
        foreach ($stmts as $stmt) {
            if ($stmt instanceof Namespace_ && $stmt->name) {
                $namespace = $stmt->name->toString();
                foreach ($stmt->stmts as $node) {
                    if (($node instanceof Class_ || $node instanceof Interface_ || $node instanceof Enum_) && $node->name) {
                        $className = $node->name->toString();
                        break;
                    }
                }
            }
        }
        return ($namespace && $className) ? $namespace . '\\' . $className : '';
    }


}
